#pragma once

#include <mcp/config.h>
#include <mcp/forward.h>
#include <mcp/types.h>
#include <mcp/error.h>

#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
#include <optional>

namespace mcp {
namespace server {

/// @brief Tool registration information
struct ToolRegistration {
    std::string name;
    std::string description;
    json::Schema input_schema;
    std::optional<json::Schema> output_schema;
    types::ToolAnnotations annotations;
    std::function<Result<json::Value>(const json::Value&, Context<>&)> handler;

    ToolRegistration() = default;
    ToolRegistration(std::string name,
                    std::string description,
                    json::Schema input_schema,
                    std::optional<json::Schema> output_schema,
                    types::ToolAnnotations annotations,
                    std::function<Result<json::Value>(const json::Value&, Context<>&)> handler)
        : name(std::move(name))
        , description(std::move(description))
        , input_schema(std::move(input_schema))
        , output_schema(std::move(output_schema))
        , annotations(std::move(annotations))
        , handler(std::move(handler)) {}
};

/// @brief Tool result
struct ToolResult {
    std::vector<std::shared_ptr<types::ContentBlock>> content;
    bool is_error = false;
    std::optional<json::Value> structured_content;
};

/// @brief Manager for MCP tools
class ToolManager {
public:
    ToolManager();
    ~ToolManager();

    /// @brief Register a new tool
    /// @param registration Tool registration information
    /// @return true if registration succeeded, false if tool already exists
    bool register_tool(ToolRegistration registration);

    /// @brief Unregister a tool
    /// @param name Tool name to unregister
    /// @return true if unregistration succeeded, false if tool not found
    bool unregister_tool(const std::string& name);

    /// @brief Check if a tool exists
    /// @param name Tool name
    /// @return true if tool exists, false otherwise
    bool has_tool(const std::string& name) const;

    /// @brief Get all registered tools
    /// @return List of tool definitions
    std::vector<types::Tool> list_tools() const;

    /// @brief Get a specific tool definition
    /// @param name Tool name
    /// @return Tool definition if found, std::nullopt otherwise
    std::optional<types::Tool> get_tool(const std::string& name) const;

    /// @brief Call a tool by name
    /// @param name Tool name
    /// @param arguments Tool arguments
    /// @param context MCP context for the call
    /// @return Tool result or error
    Result<ToolResult> call_tool(const std::string& name,
                                 const json::Value& arguments,
                                 Context<>& context);

    /// @brief Validate tool arguments against schema
    /// @param name Tool name
    /// @param arguments Arguments to validate
    /// @return Validation result
    json::ValidationResult validate_arguments(const std::string& name,
                                               const json::Value& arguments) const;

    /// @brief Get tool annotations
    /// @param name Tool name
    /// @return Tool annotations if found, std::nullopt otherwise
    std::optional<types::ToolAnnotations> get_annotations(const std::string& name) const;

    /// @brief Clear all registered tools
    void clear();

private:
    struct Impl;
    std::unique_ptr<Impl> impl_;
};

} // namespace server
} // namespace mcp